import pandas as pd
from sklearn.model_selection import train_test_split  # 数据集划分
from sklearn.preprocessing import StandardScaler  # 标准化
from sklearn.linear_model import LinearRegression  # 线性回归_正规方程法
from sklearn.linear_model import SGDRegressor  # 线性回归_随机梯度下降算法
from sklearn.metrics import mean_squared_error, mean_absolute_error, root_mean_squared_error  # 回归问题的评估指标


def liner_ml():
    # 1- 准备数据
    boston_df = pd.read_excel("boston_house_prices.xlsx")

    # 2- 数据基本处理
    # 本案例中，数据文件的最后一列是目标值
    # 拆分得到特征数据和目标数据
    x = boston_df.iloc[:, :-1]
    y = boston_df.iloc[:, -1]

    # 3- 特征工程
    # 3.1- 样本数据划分得到训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=723)

    # 3.2- 创建标准化处理的实例对象
    transformer = StandardScaler()
    new_x_train = transformer.fit_transform(x_train)
    new_x_test = transformer.transform(x_test)

    # 4- 机器学习
    # 4.1- 创建线性回归算法模型实例对象
    model = LinearRegression()

    # 4.2- 训练模型
    model.fit(new_x_train, y_train)

    # 5- 模型评估
    # 5.1- 对测试集进行预测
    y_predict = model.predict(new_x_test)

    # 5.2- MSE、MAE、RMSE
    print("MSE均方误差", mean_squared_error(y_test, y_predict))
    print("MAE平均绝对误差", mean_absolute_error(y_test, y_predict))
    print("RMSE均方根误差", root_mean_squared_error(y_test, y_predict))


def sgd_ml():
    # 1- 准备数据
    boston_df = pd.read_excel("boston_house_prices.xlsx")

    # 2- 数据基本处理
    # 本案例中，数据文件的最后一列是目标值
    # 拆分得到特征数据和目标数据
    x = boston_df.iloc[:, :-1]
    y = boston_df.iloc[:, -1]

    # 3- 特征工程
    # 3.1- 样本数据划分得到训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=723)

    # 3.2- 创建标准化处理的实例对象
    transformer = StandardScaler()
    new_x_train = transformer.fit_transform(x_train)
    new_x_test = transformer.transform(x_test)

    # 4- 机器学习
    # 4.1- 创建线性回归算法模型实例对象
    """
        参数解释
            fit_intercept：是否要截距。推荐设置为True
            random_state：随机数种子
            learning_rate：学习率的变化策略
                constant：常数。学习率固定为一个常数值
                invscaling：学习率会逐步减小
            eta0：设置梯度下降的学习率的值。如果learning_rate=constant，那么学习率设置为多少就固定是多少；
                如果learning_rate=invscaling，那么学习率会根据eta = eta0 / pow(t, power_t)公式减小

            注意：alpha参数并不是梯度下降的学习率，是正则化的惩罚系数
    """
    model = SGDRegressor(
        fit_intercept=True,
        random_state=723,
        learning_rate="constant",
        eta0=0.001
    )

    # 4.2- 训练模型
    model.fit(new_x_train, y_train)

    # 5- 模型评估
    # 5.1- 对测试集进行预测
    y_predict = model.predict(new_x_test)

    # 5.2- MSE、MAE、RMSE
    print("MSE均方误差", mean_squared_error(y_test, y_predict))
    print("MAE平均绝对误差", mean_absolute_error(y_test, y_predict))
    print("RMSE均方根误差", root_mean_squared_error(y_test, y_predict))


if __name__ == '__main__':
    # 正规方程法
    liner_ml()

    print("-" * 50)

    # 梯度下降法
    sgd_ml()